package co.fitstart.admin.service.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.demo2do.core.BusinessException;
import com.demo2do.core.persistence.GenericDaoSupport;
import com.demo2do.core.persistence.annotation.Dynamic;
import com.demo2do.core.utils.DateFormatUtils;
import com.demo2do.core.utils.DateUtils;

import co.fitstart.admin.dao.CoachDao;
import co.fitstart.admin.dao.CoachRestCalendarDao;
import co.fitstart.admin.dao.CourseScheduleDao;
import co.fitstart.admin.dao.ReportDao;
import co.fitstart.admin.service.RestCalendarService;
import co.fitstart.entity.coach.CoachRestCalendar;
import co.fitstart.entity.coach.CoachRestType;
import co.fitstart.entity.course.schedule.CourseSchedule;
import co.fitstart.entity.principal.Principal;
import co.fitstart.entity.site.Site;

/**
 * 
 * @author mohanlan
 *
 */
@Service("restCalendarService")
public class RestCalendarServiceImpl implements RestCalendarService {
    
    @Dynamic
    private CoachDao coachDao;
    
    @Dynamic
    private CourseScheduleDao courseScheduleDao;
    
    @Dynamic
    private ReportDao reportDao;
    
    @Dynamic
    private CoachRestCalendarDao coachRestCalendarDao;
    
    @Autowired
    private GenericDaoSupport genericDaoSupport;
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.RestCalendarService#listRestCalendar(co.fitstart.entity.site.Site, co.fitstart.entity.principal.Principal, java.util.Date, java.util.Date)
     */
    @SuppressWarnings("unchecked")
    public List<CoachRestCalendar> listRestCalendar(Site site, Principal coach, Date beginDate, Date endDate) {
        
        String sentence = "FROM CoachRestCalendar coachRestCalendar WHERE coachRestCalendar.disabled = false AND coachRestCalendar.coach.disabled = false AND coachRestCalendar.restDate >= :beginDate AND coachRestCalendar.restDate <= :endDate AND coachRestCalendar.coachRestType != 1  AND coachRestCalendar.coachRestType != 4";
        
        Map<String, Object> parameters = new HashMap<String, Object>();
        parameters.put("beginDate", beginDate);
        parameters.put("endDate", endDate);
        
        if(coach != null) {
            parameters.put("coach", coach);
            sentence = sentence + " AND coachRestCalendar.coach = :coach";
        }
        
        if(site != null && coach == null) {
            
            Principal manager = site.getManager();
            
            List<Long> coachIds = coachDao.coacheIds(manager);
            
            if(CollectionUtils.isNotEmpty(coachIds)) {
                sentence = sentence + " AND coachRestCalendar.coach.id in (:coachIds)";
                parameters.put("coachIds", coachIds);
            }else {
                return new ArrayList<CoachRestCalendar>();
            }
        }
        
        sentence = sentence + " ORDER BY restHour";
        
        return genericDaoSupport.searchForList(sentence, parameters);
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.RestCalendarService#listRestCalendar(java.util.List, co.fitstart.entity.principal.Principal, java.util.Date, java.util.Date)
     */
    @SuppressWarnings("unchecked")
    public List<CoachRestCalendar> listRestCalendar(List<Site> sites, Principal coach, Date beginDate, Date endDate) {
    	
        String sentence = "FROM CoachRestCalendar coachRestCalendar WHERE coachRestCalendar.disabled = false AND coachRestCalendar.coach.disabled = false AND coachRestCalendar.restDate >= :beginDate AND coachRestCalendar.restDate <= :endDate AND coachRestCalendar.coachRestType != 1 AND coachRestCalendar.coachRestType != 4";
        
        Map<String, Object> parameters = new HashMap<String, Object>();
        parameters.put("beginDate", beginDate);
        parameters.put("endDate", endDate);
        
        if(coach != null) {
            parameters.put("coach", coach);
            sentence = sentence + " AND coachRestCalendar.coach = :coach";
        }
        
        List<Long> coachIds = coachDao.coacheIds(sites);
        
        if(CollectionUtils.isNotEmpty(coachIds)) {
            sentence = sentence + " AND coachRestCalendar.coach.id in (:coachIds)";
            parameters.put("coachIds", coachIds);
        }else {
            return new ArrayList<CoachRestCalendar>();
        }
        
        sentence = sentence + " ORDER BY restHour";
        
        return genericDaoSupport.searchForList(sentence, parameters);
    }

      /**
       * 
       * @param coach
       * @param coachRestType
       * @param restDate
       * @param restHour
       */
      private void createRestCalendars(Principal coach, CoachRestType coachRestType, Date restDate, String[] restHours) {
        List<CoachRestType> coachRestTypes = coachDao.getCoachRestCalendar(coach, restDate, restHours);
        if((coachRestType.isDuty() && coachRestTypes.contains(CoachRestType.DUTY)) || (coachRestType.isBusiness() && coachRestTypes.contains(CoachRestType.BUSINESS)) || (coachRestType.isExperience() && coachRestTypes.contains(CoachRestType.EXPERIENCE))) {
            throw new BusinessException("该值班时间已存在");
        } else if (coachRestType.isDuty() && (coachRestTypes.contains(CoachRestType.REST) || coachRestTypes.contains(CoachRestType.ANNUAL_LEAVE))) {
            throw new BusinessException("该时间为教练休息时间");
        } else if ((coachRestType.isBusiness() || coachRestType.isExperience()) && !coachRestTypes.isEmpty() && !(coachRestTypes.size() == 1 && coachRestTypes.contains(CoachRestType.DUTY))) {
            throw new BusinessException("该时间教练已有其他休息");
        }
        
        if(coachRestType.isBusiness() || coachRestType.isExperience()) {
            List<CourseSchedule> courseSchedules = courseScheduleDao.listCourseSchedule(coach, restDate, restHours);
            if(courseSchedules != null && courseSchedules.size() != 0) {
                throw new BusinessException("该时间教练已有课程");
            }
        }
        
        for(String restHour : restHours) {
            CoachRestCalendar calendar = new CoachRestCalendar(coach, coachRestType, restDate, restHour, false);
            genericDaoSupport.save(calendar);
        }
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.RestCalendarService#deleteRestCalendar(co.fitstart.entity.principal.Principal, java.util.Date)
     */
    public void deleteRestCalendar(Principal coach, Date restDate) {
        List<CoachRestCalendar> coachRestCalendars = coachDao.listDutyOrBusinessHour(coach, restDate);
        for(CoachRestCalendar coachRestCalendar : coachRestCalendars) {
          genericDaoSupport.update(coachRestCalendar.disable());
        }
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.RestCalendarService#editRestCalendar(co.fitstart.entity.principal.Principal, co.fitstart.entity.coach.CoachRestType, java.util.Date, java.lang.String)
     */
    public void editRestCalendar(Principal coach, CoachRestType coachRestType, Date RDate, String restHour,List<String> restDates) {
        
        // 1.disable old restCalendar first
        Date currentDate = DateUtils.parseDate(DateFormatUtils.format(new Date(), "yyyy-MM-dd"), "yyyy-MM-dd");
        
        //批量修改多天的休息时间
        if(restDates !=null) {
        	
        	for (String restDate : restDates) {
            	
            	Date rd = DateUtils.parseDate(restDate, "yyyy-MM-dd");
            	 
                if(currentDate.equals(rd)) {
                    String currentHour = DateFormatUtils.format(new Date(), "HH:mm");
                    coachDao.deleteCoachRestCalendar(coach, coachRestType, rd, currentHour);
                } else {
                    coachDao.deleteCoachRestCalendar(coach, coachRestType, rd);
                }
                
                // 2.create new restCalendar
                if(StringUtils.isNotEmpty(restHour)) {
                    String[] restHours = StringUtils.split(restHour, ",");
                    this.createRestCalendars(coach, coachRestType, rd, restHours);
                }
            }
        }else {
        	//当天的休息时间
       	 
            if(currentDate.equals(RDate)) {
                String currentHour = DateFormatUtils.format(new Date(), "HH:mm");
                coachDao.deleteCoachRestCalendar(coach, coachRestType, RDate, currentHour);
            } else {
                coachDao.deleteCoachRestCalendar(coach, coachRestType, RDate);
            }
            
            // 2.create new restCalendar
            if(StringUtils.isNotEmpty(restHour)) {
                String[] restHours = StringUtils.split(restHour, ",");
                this.createRestCalendars(coach, coachRestType, RDate, restHours);
            }
        	
        }
        
       
        
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.RestCalendarService#editBatchSchedule(java.lang.String, java.util.Date, java.util.Date, java.util.Date, java.util.Date, co.fitstart.entity.coach.CoachRestType, java.lang.String, java.lang.String, java.lang.String, java.lang.String)
     */
    public void editBatchSchedule(String coach, Date trainingDate, Date conferenceDate, Date businessDate, Date dutyDate, String trainingHour, String conferenceHour, String businessHour, String dutyHour) {
        
        Date today = new Date();
        
        // 为防止教练未选，input hidden 会添加一个空格与逗号 
        if(coach.trim().isEmpty()){
            throw new BusinessException("请至少选择一个教练");
        }
        
        coach = coach.trim().substring(1);
        String[] coaches = StringUtils.split(coach, ",");
        
        if(StringUtils.isNotEmpty(businessHour) && businessDate != null) {
            String[] businessHours = StringUtils.split(businessHour, ",");
            for(String coachId : coaches) {
                Principal principal = genericDaoSupport.load(Principal.class, Long.parseLong(coachId));
                for(String restHour : businessHours) {
                    Date thisDate = DateUtils.parseDate(DateFormatUtils.format(businessDate, "yyyy-MM-dd") + " " + restHour, "yyyy-MM-dd HH:mm");
                    if(thisDate.before(today)) {
                        throw new BusinessException("选中时间小于当前时间");
                    }
                }
                this.createRestCalendars(principal, CoachRestType.BUSINESS, businessDate, businessHours);
                
            }
        }
        
        if(StringUtils.isNotEmpty(conferenceHour) && conferenceDate != null) {
            String[] conferenceHours = StringUtils.split(conferenceHour, ",");
            for(String coachId : coaches) {
                Principal principal = genericDaoSupport.load(Principal.class, Long.parseLong(coachId));
                for(String restHour : conferenceHours) {
                    Date thisDate = DateUtils.parseDate(DateFormatUtils.format(conferenceDate, "yyyy-MM-dd") + " " + restHour, "yyyy-MM-dd HH:mm");
                    if(thisDate.before(today)) {
                        throw new BusinessException("选中时间小于当前时间");
                    }
                }
                this.createRestCalendars(principal, CoachRestType.CONFERENCE, conferenceDate, conferenceHours);
                
            }
        }
        
        if(StringUtils.isNotEmpty(trainingHour) && trainingDate != null) {
            String[] trainingHours = StringUtils.split(trainingHour, ",");
            for(String coachId : coaches) {
                Principal principal = genericDaoSupport.load(Principal.class, Long.parseLong(coachId));
                for(String restHour : trainingHours) {
                    Date thisDate = DateUtils.parseDate(DateFormatUtils.format(trainingDate, "yyyy-MM-dd") + " " + restHour, "yyyy-MM-dd HH:mm");
                    if(thisDate.before(today)) {
                        throw new BusinessException("选中时间小于当前时间");
                    }
                }
                this.createRestCalendars(principal, CoachRestType.TRAINING, trainingDate, trainingHours);
                
            }
        }
        
        if(StringUtils.isNotEmpty(dutyHour) && dutyDate != null) {
            String[] dutyHours = StringUtils.split(dutyHour, ",");
            for(String coachId : coaches) {
                Principal principal = genericDaoSupport.load(Principal.class, Long.parseLong(coachId));
                for(String restHour : dutyHours) {
                    Date thisDate = DateUtils.parseDate(DateFormatUtils.format(dutyDate, "yyyy-MM-dd") + " " + restHour, "yyyy-MM-dd HH:mm");
                    if(thisDate.before(today)) {
                        throw new BusinessException("选中时间小于当前时间");
                    }
                }
                this.createRestCalendars(principal, CoachRestType.DUTY, dutyDate, dutyHours);
                
            }
        }
        
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.RestCalendarService#editBatchSchedule(java.lang.String, java.util.Date, co.fitstart.entity.coach.CoachRestType, java.lang.String)
     */
    public void editBatchSchedule(String coach, Date date, CoachRestType coachRestType, String hour) {
        Date today = new Date();
        
        // 为防止教练未选，input hidden 会添加一个空格与逗号 
        if(coach.trim().isEmpty()){
        	throw new BusinessException("请至少选择一个教练");
        }
        
        coach = coach.trim().substring(1);
        
        String[] coaches = StringUtils.split(coach, ",");
        String[] restHours = StringUtils.split(hour, ",");
        
        for(String coachId : coaches) {
            Principal principal = genericDaoSupport.load(Principal.class, Long.parseLong(coachId));
            for(String restHour : restHours) {
                Date thisDate = DateUtils.parseDate(DateFormatUtils.format(date, "yyyy-MM-dd") + " " + restHour, "yyyy-MM-dd HH:mm");
                if(thisDate.before(today)) {
                    throw new BusinessException("选中时间小于当前时间");
                }
            }
            this.createRestCalendars(principal, coachRestType, date, restHours);
            
        }
        
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.RestCalendarService#batchBusinessCalendar(java.lang.String, java.util.Date, java.lang.String)
     */
    public void batchBusinessCalendar(String coach, Date date, String hour) {
        Date today = new Date();
        
        String[] coaches = StringUtils.split(coach, ",");
        String[] restHours = StringUtils.split(hour, ",");
        
        for(String coachId : coaches) {
            Principal principal = genericDaoSupport.load(Principal.class, Long.parseLong(coachId));
            Site site = coachDao.getCoachRelation(principal);
            List<String> siteTimes = site.getBusinessTimes();
            for(String restHour : restHours) {
                if(!siteTimes.contains(restHour)) {
                    throw new BusinessException("选中时间不在门店营业时间");
                }
                
                Date thisDate = DateUtils.parseDate(DateFormatUtils.format(date, "yyyy-MM-dd") + " " + restHour, "yyyy-MM-dd HH:mm");
                if(thisDate.before(today)) {
                    throw new BusinessException("选中时间小于当前时间");
                }
            }
            this.createRestCalendars(principal, CoachRestType.BUSINESS, date, restHours);
        }
    }

    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.RestCalendarService#editAnnualLeave(co.fitstart.entity.principal.Principal, java.util.Date, java.util.Date)
     */
    public void editAnnualLeave(Principal coach, Date beginDate, Date endDate) {
        // 1. delete repeat coachRestCalendar
        coachRestCalendarDao.disableRepeatAnnualLeave(coach, beginDate, endDate);
        
        // get coach's site
        Site site = coachDao.getCoachRelation(coach);
        
        // get annual leave times
        List<Date> times = this.getAnnualLeaveTimes(site, beginDate, endDate);
        
        // validate times
        this.validateTimes(coach, beginDate, endDate);
        
        // save annual leave times
        for (Date time : times) {
            CoachRestCalendar calendar = new CoachRestCalendar(coach, CoachRestType.ANNUAL_LEAVE, DateUtils.parseDate(DateFormatUtils.format(time, "yyyy-MM-dd"), "yyyy-MM-dd"), DateFormatUtils.format(time, "HH:mm"), false);
            genericDaoSupport.save(calendar);
        }
    }
    
    /**
     * 
     * @param site
     * @param beginDate
     * @param endDate
     * @return
     */
    private List<Date> getAnnualLeaveTimes(Site site, Date beginDate, Date endDate) {
        
        List<Date> times = new ArrayList<Date>();
        
        beginDate = DateUtils.parseDate(DateFormatUtils.format(beginDate, "yyyy-MM-dd") + " " + site.getBusinessStartHour() + ":00", "yyyy-MM-dd HH:mm:ss");
        endDate = DateUtils.parseDate(DateFormatUtils.format(endDate, "yyyy-MM-dd") + " " + site.getBusinessEndHour() + ":00", "yyyy-MM-dd HH:mm:ss");
        
        Date businessStart = DateUtils.parseDate(DateFormatUtils.format(new Date(), "yyyy-MM-dd") + " " + site.getBusinessStartHour() + ":00", "yyyy-MM-dd HH:mm:ss");
        Date businessEnd = DateUtils.parseDate(DateFormatUtils.format(new Date(), "yyyy-MM-dd") + " " + site.getBusinessEndHour() + ":00", "yyyy-MM-dd HH:mm:ss");
        
        while (beginDate.getTime() < endDate.getTime()) {
            Date date = DateUtils.parseDate(DateFormatUtils.format(new Date(), "yyyy-MM-dd") + " " + DateFormatUtils.format(beginDate, "HH:mm:ss"), "yyyy-MM-dd HH:mm:ss");
            if(!date.before(businessStart) && !date.after(businessEnd)) {
                times.add(beginDate);
            }
            beginDate = org.apache.commons.lang3.time.DateUtils.addMinutes(beginDate, 30);
        }
        return times;
    }
    
    /**
     * 
     * @param coach
     * @param beginDate
     * @param endDate
     */
    private void validateTimes(Principal coach, Date beginDate, Date endDate) {
        
        // validate rest calendar first
        List<CoachRestCalendar> restCalendars = coachRestCalendarDao.list(coach, beginDate, endDate);
        if(!restCalendars.isEmpty()) {
            throw new BusinessException("该时间已有其他休息，请重新选择!");
        }
        
        // validate course schedule
        List<CourseSchedule> courseSchedules = courseScheduleDao.listCourseSchedule(coach, beginDate, endDate);
        if(!courseSchedules.isEmpty()) {
            throw new BusinessException("该时间已有课程，请重新选择!");
        }
        
    }

    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.RestCalendarService#editExperience(co.fitstart.entity.principal.Principal, java.lang.Long, java.util.Date, java.lang.String, java.lang.String, java.lang.String)
     */
	public void editExperience(Principal coach, Long expCourseId, Date restDate, String restHour, String expUserMobile,
			String expUserName) {
		// TODO Auto-generated method stub
		
	}
}
